/**
Implements the main function for the server.
*/
#include "globals.h"

extern void* echo_thread_func(void* arg);
extern void* time_thread_func(void* arg);

/**
The main function.
*/
int 
main(
    int argc,
    char *argv[]
    )
{
    int sockfd_echo;
    int sockfd_time;
    
    int max_fd;
    int client[FD_SETSIZE];
    
    fd_set rset;
    
    socklen_t cli_len_echo;
    socklen_t cli_len_time;
    socklen_t len;
    
    struct sockaddr* cli_addr_echo;
    struct sockaddr* cli_addr_time;

    pthread_t tid_echo;
    pthread_t tid_time;

    int* fd_ptr;

    int flags_echo;
    int flags_time;

    //
    // Use the protocol independent wrapper.
    //

    sockfd_echo = Tcp_listen_ext(NULL, PORT_NUM_ECHO_STR, &cli_len_echo);
    sockfd_time = Tcp_listen_ext(NULL, PORT_NUM_TIME_STR, &cli_len_time);

    FD_ZERO(&rset);

    cli_addr_echo = Malloc(cli_len_echo);
    cli_addr_time = Malloc(cli_len_time);

    //
    // All SIGPIPE errors will be caught in write operations as EPIPE errors.
    //

    Signal(SIGPIPE, SIG_IGN);

    while(TRUE)
    {
        FD_SET(sockfd_echo, &rset);
        FD_SET(sockfd_time, &rset);

        //
        // We are interested when any of the listening sockets (echo/time)
        // become readable.
        //

        max_fd = max(sockfd_echo, sockfd_time) + 1;
        Select(max_fd, &rset, NULL, NULL, NULL);

        //
        // Received request from echo client.
        //

        if (FD_ISSET(sockfd_echo, &rset))
        {
            log_server(DIAG_ECHO_CLIENT_CONN);                    
            len = cli_len_echo;
            fd_ptr = Malloc(sizeof(int));
            *fd_ptr = Accept(sockfd_echo, cli_addr_echo, &len);

            //
            // Not nonblocking any more.
            //

            if ((flags_echo = fcntl (*fd_ptr, F_GETFL, 0)) < 0)
            {
                err_sys("F_GETFL error");
            }

            flags_echo &= ~O_NONBLOCK;

            if (fcntl(*fd_ptr, F_SETFL, flags_echo) < 0)
            {
                err_sys("F_SETFL error");
            }

            Pthread_create(&tid_echo, NULL, &echo_thread_func, fd_ptr); 
        }
        
        //
        // Day time client.
        //

        if (FD_ISSET(sockfd_time, &rset))
        {
            log_server(DIAG_TIME_CLIENT_CONN); 
            len = cli_len_time;
            fd_ptr = Malloc(sizeof(int));
            *fd_ptr = Accept(sockfd_time, cli_addr_time, &len);

            if  ((flags_time = fcntl (*fd_ptr, F_GETFL, 0)) < 0)
            {
                err_sys("F_GETFL error");
            }

            flags_time &= ~O_NONBLOCK;

            if (fcntl(*fd_ptr, F_SETFL, flags_time) < 0)
            {
                err_sys("F_SETFL error");
            }

            Pthread_create(&tid_time, NULL, &time_thread_func, fd_ptr); 
        }
    }

    return 0;
}

